import { useEffect, useMemo, useRef, useState } from 'react'
import type { TouchEvent, MouseEvent } from 'react'
import { useInfiniteQuery, useQueryClient } from '@tanstack/react-query'
import dayjs from 'dayjs'

import { DiaryAPI } from '../app/api'
import type { ApiDiaryEntry } from '../app/types'
import DiaryComposerDialog from '../components/DiaryComposerDialog'
import PageHeader from '../components/PageHeader'
import Button from '../components/ui/Button'
import { Card } from '../components/ui/Card'
import { useNavigate } from 'react-router-dom'
import { KebabMenu } from '../components/ui/Menu'
import { PencilSquareIcon, TrashIcon } from '@heroicons/react/24/outline'
import useConfirmDialog from '../components/ui/useConfirmDialog'

const PAGE_SIZE = 10

const DiaryPage = () => {
  if (typeof document !== 'undefined') document.title = '恋爱日记 · Love Notes'
  const [composerOpen, setComposerOpen] = useState(false)
  const [editing, setEditing] = useState<null | ApiDiaryEntry>(null)
  const navigate = useNavigate()
  const queryClient = useQueryClient()
  const [confirm, ConfirmDialog] = useConfirmDialog()
  const [activeActionId, setActiveActionId] = useState<number | null>(null)
  const hideTimerRef = useRef<number | null>(null)

  useEffect(() => {
    if (activeActionId === null) return
    if (hideTimerRef.current) window.clearTimeout(hideTimerRef.current)
    hideTimerRef.current = window.setTimeout(() => setActiveActionId(null), 3000)
    return () => {
      if (hideTimerRef.current) {
        window.clearTimeout(hideTimerRef.current)
        hideTimerRef.current = null
      }
    }
  }, [activeActionId])

  const {
    data,
    isLoading,
    fetchNextPage,
    hasNextPage,
    isFetchingNextPage,
  } = useInfiniteQuery({
    queryKey: ['diary', 'list'],
    initialPageParam: 0,
    queryFn: ({ pageParam = 0 }) => DiaryAPI.list({ limit: PAGE_SIZE, offset: pageParam }),
    getNextPageParam: (lastPage) => lastPage.next_offset ?? undefined,
  })

  const diaries = useMemo(() => data?.pages.flatMap((page) => page.items) ?? [], [data])
  const loadMoreRef = useRef<HTMLDivElement | null>(null)

  useEffect(() => {
    const node = loadMoreRef.current
    if (!node) return
    const observer = new IntersectionObserver(
      (entries) => {
        const [entry] = entries
        if (entry?.isIntersecting && hasNextPage && !isFetchingNextPage) {
          fetchNextPage()
        }
      },
      { rootMargin: '200px 0px 200px 0px' },
    )
    observer.observe(node)
    return () => observer.disconnect()
  }, [fetchNextPage, hasNextPage, isFetchingNextPage])

  return (
    <div className="space-y-6">
      <PageHeader
        eyebrow="Diary"
        title="恋爱日记时间线"
        description="记录心跳瞬间、分享细腻感受。每篇日记都可决定是否通知伴侣或保持专属私密。"
        actions={
          <Button onClick={() => setComposerOpen(true)} size="sm">
            创建新日记
          </Button>
        }
      />
      <Card padding="lg" className="space-y-4" title="时间线" description="最新的日记会排在最前，点击卡片可查看详情和评论。">
        {isLoading ? (
          <p className="text-sm text-slate-400">日记加载中...</p>
        ) : diaries.length === 0 ? (
          <div className="rounded-2xl border border-dashed border-slate-200 bg-slate-50/80 p-6 text-center text-sm text-slate-500">
            还没有日记记录，点击「创建新日记」开始记录彼此的故事。
          </div>
        ) : (
          <>
            {diaries.map((entry, index) => (
              <DiaryCard
                key={entry.id}
                entry={entry}
                index={index}
                total={diaries.length}
                onClick={() => {
                  setActiveActionId(null)
                  navigate(`/diary/${entry.id}`)
                }}
                onEdit={() => {
                  setActiveActionId(null)
                  setEditing(entry)
                }}
                onDelete={async () => {
                  const confirmed = await confirm({
                    title: '删除日记',
                    description: '删除后无法恢复，确定要删除这篇日记吗？',
                    confirmText: '确定删除',
                    cancelText: '取消',
                  })
                  if (!confirmed) return
                  await DiaryAPI.remove(entry.id)
                  setActiveActionId(null)
                  queryClient.invalidateQueries({ queryKey: ['diary', 'list'] })
                  queryClient.invalidateQueries({ queryKey: ['diary', entry.id, 'entry'] })
                }}
                showActions={activeActionId === entry.id}
                onShowActions={() => setActiveActionId(entry.id)}
                onHideActions={() => setActiveActionId(null)}
              />
            ))}
            <div ref={loadMoreRef} className="h-6" />
            {isFetchingNextPage ? (
              <p className="text-center text-xs text-slate-400">加载更多中...</p>
            ) : null}
            {!hasNextPage && diaries.length > 0 ? (
              <p className="text-center text-xs text-slate-300">没有更多日记了</p>
            ) : null}
          </>
        )}
      </Card>
      <DiaryComposerDialog open={composerOpen} onClose={() => setComposerOpen(false)} />
      {editing ? (
        <DiaryComposerDialog
          open={true}
          onClose={() => setEditing(null)}
          entry={{
            id: editing.id,
            title: editing.title,
            content_md: editing.content_md,
            mood: editing.mood,
            tags: editing.tags,
            visibility: editing.visibility,
          }}
        />
      ) : null}
      <ConfirmDialog />
    </div>
  )
}

const DiaryCard = ({
  entry,
  index,
  total,
  onClick,
  onEdit,
  onDelete,
  showActions,
  onShowActions,
  onHideActions,
}: {
  entry: ApiDiaryEntry
  index: number
  total: number
  onClick: () => void
  onEdit: () => void
  onDelete: () => void
  showActions: boolean
  onShowActions: () => void
  onHideActions: () => void
}) => {
  const longPressTimer = useRef<number | null>(null)
  const longPressTriggered = useRef(false)

  const clearTimer = () => {
    if (longPressTimer.current) {
      window.clearTimeout(longPressTimer.current)
      longPressTimer.current = null
    }
  }

  const handleTouchStart = () => {
    longPressTriggered.current = false
    clearTimer()
    longPressTimer.current = window.setTimeout(() => {
      longPressTriggered.current = true
      onShowActions()
    }, 350)
  }

  const handleTouchMove = () => {
    if (longPressTimer.current) {
      clearTimer()
    }
  }

  const handleTouchEnd = (event: TouchEvent) => {
    clearTimer()
    if (longPressTriggered.current) {
      event.preventDefault()
      longPressTriggered.current = false
      return
    }
    handleCardClick()
  }

  const handleCardClick = () => {
    if (showActions) {
      onHideActions()
      return
    }
    onClick()
  }

  const handleContextMenu = (event: MouseEvent) => {
    event.preventDefault()
    onShowActions()
  }

  return (
    <article
      onClick={handleCardClick}
      onContextMenu={handleContextMenu}
      onTouchStart={handleTouchStart}
      onTouchEnd={handleTouchEnd}
      onTouchMove={handleTouchMove}
      className="relative cursor-pointer surface-card p-6 transition-transform duration-200 hover:-translate-y-0.5"
    >
      {showActions ? (
        <div
          className="absolute right-4 top-4 z-20 flex items-center gap-2 rounded-full bg-white/95 px-2 py-1 shadow-md ring-1 ring-slate-200"
          onClick={(event) => event.stopPropagation()}
        >
          <button
            className="flex h-8 w-8 items-center justify-center rounded-full text-slate-500 transition hover:text-slate-700"
            onClick={(event) => {
              event.stopPropagation()
              onHideActions()
              onEdit()
            }}
          >
            <PencilSquareIcon className="h-4 w-4" />
          </button>
          <span className="h-6 w-px bg-slate-200" aria-hidden />
          <button
            className="flex h-8 w-8 items-center justify-center rounded-full text-red-500 transition hover:text-red-600"
            onClick={(event) => {
              event.stopPropagation()
              onDelete()
            }}
          >
            <TrashIcon className="h-4 w-4" />
          </button>
        </div>
      ) : null}
      <span
        className="pointer-events-none absolute left-6 top-7 hidden h-10 w-10 -translate-x-1/2 rounded-full bg-blush-300/25 blur-xl sm:block"
        aria-hidden
      />
      <span
        className="pointer-events-none absolute left-6 top-7 hidden h-3 w-3 -translate-x-1/2 rounded-full bg-gradient-to-br from-blush-400 via-lavender-400 to-sky-400 shadow-[0_0_0_4px_rgba(255,238,245,0.65)] sm:block"
        aria-hidden
      />
      <div className="flex flex-col gap-4 sm:flex-row sm:items-start sm:justify-between">
        <div>
          <p className="text-sm font-medium text-blush-400">
            {entry.created_at ? dayjs(entry.created_at).format('YYYY 年 MM 月 DD 日 HH:mm') : '时间未知'}
          </p>
          <span className="mt-2 block text-base font-semibold group-hover:text-blush-400">
            {entry.title}
          </span>
        </div>
        <div className="flex items-center gap-2">
          {entry.mood ? (
            <span className="inline-flex items-center gap-1 rounded-full border border-white/20 bg-white/10 px-3 py-1 text-xs font-medium">心情：{entry.mood}</span>
          ) : null}
          <KebabMenu
            items={[
              { label: '编辑', onSelect: onEdit },
              { label: '删除', onSelect: onDelete, danger: true },
            ]}
          />
        </div>
      </div>
      <p className="mt-4 text-sm leading-relaxed opacity-95">{entry.ai_summary ?? entry.content_md}</p>
      {(entry.tags?.length ?? 0) > 0 ? (
        <div className="mt-4 flex flex-wrap gap-2 text-xs">
          {(entry.tags ?? []).map((tag) => (
            <span key={tag} className="inline-flex items-center gap-1 rounded-full border border-white/20 bg-white/10 px-3 py-1 text-xs font-medium">
              #{tag}
            </span>
          ))}
        </div>
      ) : null}
    </article>
  )
}

export default DiaryPage
